﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SmartCard.Framework;

namespace SmartCard.PcscApi
{
	/// <summary>
	/// Discovery process for PC/SC based smart card readers
	/// </summary>
	internal class PcscSmartCardReaderDiscoveryProcess : ISmartCardReaderDiscovery
	{
		#region ISmartCardReaderDiscovery Implementation

		public IEnumerable<ISmartCardReader> Discover()
		{
			var readerNames = GetInstalledReaders();

			var readers = new LinkedList<ISmartCardReader>();
			foreach (var readerName in readerNames)
			{ readers.AddLast(CreateReader(readerName)); }

			return readers;
		}

		#endregion

		#region privates

		private PcscSmartCardReader CreateReader(string readerName)
		{
			// TODO: revisit how we will determine the reader type.  (name inference, injection, etc)
			return new PcscSmartCardReader(readerName, eReaderType.Unknown);
		}

		/// <summary>
		/// Returns the string names of all of the smart card readers currently available on the system.
		/// </summary>
		/// <returns></returns>
		private IEnumerable<string> GetInstalledReaders()
		{
			// get the length of buffer needed for all string names
			UInt32 bufferLength = 0;
			int retVal = 0;

			// get the buffer size required for getting all readers.
			retVal = PcscInvokes.SCardListReaders(0, IntPtr.Zero, null, ref bufferLength);
			if ((ePcscErrors)retVal != ePcscErrors.Success)
			{ throw new PcscException("Error code returned from SCardListReaders while attempting to retreive buffer size", (ePcscErrors)retVal); }

			// now load the buffer up
			byte[] mszReaders = new byte[bufferLength];
			retVal = PcscInvokes.SCardListReaders(0, IntPtr.Zero, mszReaders, ref bufferLength);
			if ((ePcscErrors)retVal != ePcscErrors.Success)
			{
				throw new PcscException("Error code returned from SCardListReaders while attempting to populate buffer", (ePcscErrors)retVal);
			}

			ASCIIEncoding encoding = new ASCIIEncoding();
			string encoded = encoding.GetString(mszReaders);
			string[] split = encoded.Split('\0');
			return split.Where((x) => !string.IsNullOrWhiteSpace(x));
		}

		#endregion
	}
}
